

#include "function.h"
#include <iostream>
#include <cmath>
#include "graphics.h"

Vector3 COLOR_GREEN = { 0,255,0 };
Vector3 COLOR_RED = { 255,0,0 };
Vector3 COLOR_BLUE = { 0,0,255 };
Vector3 COLOR_YELLOW = { 255,255,0 };
Vector3 COLOR_MAGENTA = { 255,0,255 };
Vector3 COLOR_CYAN = { 0,255,255 };

void PutPixel(Vector2 p, Vector3 color)
{
	putpixel(CANVAS_WIDTH/2+p.x, CANVAS_HEIGHT/2-p.y, EGERGB(color.x, color.y, color.z), NULL);
}

bool Interpolate(int x0, int y0, int x1, int y1, int* value)
{
	if (x0 == x1) {
		value[0] = y0;
		return false;
	}
	float k = ((float)(y1 - y0))/ ((float)(x1 - x0));
	
	int num = x1 - x0;
	float y = y0;
	for (int i = 0; i <= num; i++)
	{
		value[i] = (int)y;
		y += k;
		//std::cout << y << " ";
		
	}
	return true;
}

void DrawLine(Vector2 p0, Vector2 p1, Vector3 color)
{
	int temp;
	int num;
	int* value;
	Vector2 temp_point;
	if (abs(p1.x - p0.x) > abs(p1.y - p0.y))
	{
		if (p0.x > p1.x)
		{
			temp = p0.x;
			p0.x = p1.x;
			p1.x = temp;
			temp = p0.y;
			p0.y = p1.y;
			p1.y = temp;
		}
		num = p1.x - p0.x + 1;
		value = (int*)malloc(sizeof(int) * num);
		Interpolate(p0.x,p0.y, p1.x,p1.y, value);
		if (value)
		{
			for (int i = 0; i < num; i++)
			{
				temp_point.x = p0.x + i;
				temp_point.y = *(value + i);
				PutPixel(temp_point, color);
			}
		}
		
	}
	else
	{
		if (p0.y > p1.y)
		{
			temp = p0.y;
			p0.y = p1.y;
			p1.y = temp;
			temp = p0.x;
			p0.x = p1.x;
			p1.x = temp;
		}
		num = p1.y - p0.y + 1;
		temp = p0.x;
		p0.x = p0.y;
		p0.y = temp;
		temp = p1.x;
		p1.x = p1.y;
		p1.y = temp;
		value = (int*)malloc(sizeof(int) * num);
		Interpolate(p0.x, p0.y, p1.x, p1.y, value);
		if (value)
		{
			for (int i = 0; i < num; i++)
			{
				temp_point.y = p0.x + i;
				temp_point.x = *(value + i);
				PutPixel(temp_point, color);
			}
		}
		
	}
	free(value);
}

void DrawWireframeTriangle(Vector2 p0, Vector2 p1, Vector2 p2, Vector3 color)
{
	DrawLine(p0, p1, color);
	DrawLine(p1, p2, color);
	DrawLine(p2, p0, color);

}

void DrawFilledTriangle(Vector2 p0, Vector2 p1, Vector2 p2, Vector3 color)
{
	int temp;
	if (p0.y > p1.y)
	{
		temp = p0.x;
		p0.x = p1.x;
		p1.x = temp;
		temp = p0.y;
		p0.y = p1.y;
		p1.y = temp;
	}
	if (p0.y > p2.y)
	{
		temp = p0.x;
		p0.x = p2.x;
		p2.x = temp;
		temp = p0.y;
		p0.y = p2.y;
		p2.y = temp;
	}
	if (p1.y > p2.y)
	{
		temp = p1.x;
		p1.x = p2.x;
		p2.x = temp;
		temp = p1.y;
		p1.y = p2.y;
		p2.y = temp;
	}
	int* edge_012 = (int*)malloc(sizeof(int) * (p2.y - p0.y + 1));
	int* edge_12 = (int*)malloc(sizeof(int) * (p2.y - p1.y + 1));
	int* edge_02 = (int*)malloc(sizeof(int) * (p2.y - p0.y + 1));
	Interpolate(p0.y, p0.x, p1.y, p1.x,edge_012);
	Interpolate(p1.y, p1.x, p2.y, p2.x, edge_12);
	Interpolate(p0.y, p0.x, p2.y, p2.x, edge_02);

	for (int i = p1.y - p0.y; i < (p2.y - p0.y + 1); i++)
	{
		edge_012[i] = edge_12[i - p1.y + p0.y];
	}
	
	int* left, * right;
	int mid = (p2.y - p0.y + 1) / 2;
	if (edge_012[mid] > edge_02[mid])
	{
		left = edge_02;
		right = edge_012;
	}
	else
	{
		left = edge_012;
		right = edge_02;
	}

	for (int y = p0.y; y <= p2.y; ++y)
	{
		for (int x = left[y - p0.y]; x <= right[y - p0.y]; ++x)
		{
			PutPixel({ x,y }, COLOR_GREEN );
		}
	}
	free(edge_012);
	free(edge_12);
	free(edge_02);
}

Vector2 ViewportToCanvas(Vector2 p)
{
	return { p.x * CANVAS_WIDTH / VIEWPORT_WIDTH,p.y * CANVAS_HEIGHT / VIEWPORT_HEIGHT };
}
Vector2 ProjectVertex(Vector3 p)
{
	return ViewportToCanvas({ p.x * DISTANCE / p.z, p.y * DISTANCE / p.z });
}


void RenderTriangle(Triangle triangle, Vector2 *projected)
{
	DrawWireframeTriangle(projected[triangle.vertice1], projected[triangle.vertice2],
		projected[triangle.vertice3], triangle.color);
}

void RenderObject(Vertice *vertice_list, int vertice_len, Triangle *triangle_list, int triangle_len) 
{
	Vector2* projected = (Vector2*)malloc(sizeof(Vector2) * vertice_len);
	for (int i = 0; i < vertice_len; ++i)
	{


		projected[i] = ProjectVertex((vertice_list[i].coordinate));
	}
	for (int i = 0; i < triangle_len; ++i)
	{
		RenderTriangle(triangle_list[i], projected);
	}
	free(projected);
}